Skip to content

Commit

Permalink
add view struct, remove unused filename for tables, add notes to upda…
Browse files Browse the repository at this point in the history
…te database error behavior
  • Loading branch information
giuseppe-g-gelardi committed Nov 27, 2024
1 parent de6ea32 commit aeaba4c
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 204 deletions.
173 changes: 26 additions & 147 deletions src/cargobase/database.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use serde::{Deserialize, Serialize};

use super::view::View;
use super::DatabaseError;
use super::{query::Operation, Query, Table};

Expand Down Expand Up @@ -52,23 +53,38 @@ impl Database {
Ok(())
}

// TODO: update this:
/*
* if the table does not exist, add it to the Database
*
* if the table exists:
* -- do NOT add a duplicate to the db
* -- let the user know that the table already exists
* -- do NOT crash the program, just return and move on
*/
pub fn add_table(&mut self, table: &mut Table) -> Result<(), DatabaseError> {
table.set_file_name(self.file_name.clone());
// table.set_file_name(self.file_name.clone());
if self.tables.iter().any(|t| t.name == table.name) {
return Err(DatabaseError::TableAlreadyExists(table.name.clone()));
}
// IF the table does not exist, add it to the database
// IF the table exists:
// -- do NOT add a duplicate to the db
// -- let the user know that the table already exists
// -- do NOT crash the program, just return and move on

self.tables.push(table.clone());
self.save_to_file()
.map_err(|e| DatabaseError::SaveError(e))?;
Ok(())
}

// TODO: update this:
/*
* IF the table does not exist:
* -- let the user know that the table does not exist
* -- do NOT crash the program, just return and move on
*
* IF the table exists:
* -- remove the table from the db
* -- save the db to file
* -- let the user know that the table was removed successfully
*/
pub fn drop_table(&mut self, table_name: &str) -> Result<(), DatabaseError> {
let mut db =
Database::load_from_file(&self.file_name).map_err(|e| DatabaseError::LoadError(e))?;
Expand All @@ -78,15 +94,6 @@ impl Database {
println!("Table `{}` dropped successfully", removed_table.name);
db.save_to_file().map_err(|e| DatabaseError::SaveError(e))?;

// IF the table does not exist:
// -- let the user know that the table does not exist
// -- do NOT crash the program, just return and move on
//
// IF the table exists:
// -- remove the table from the db
// -- save the db to file
// -- let the user know that the table was removed successfully

self.tables = db.tables;
Ok(())
} else {
Expand Down Expand Up @@ -164,141 +171,13 @@ impl Database {
}

pub fn view(&self) {
println!("Database: {}", self.name);

for table in &self.tables {
println!("\nTable: {}", table.name);

if table.columns.0.is_empty() {
println!("No columns defined for table '{}'.", table.name);
continue;
}

// Get column names and determine maximum width for each column
let column_names: Vec<&str> = table
.columns
.0
.iter()
.map(|col| col.name.as_str())
.collect();
let mut column_widths: Vec<usize> =
column_names.iter().map(|name| name.len()).collect();

// Adjust column widths based on the content of each row
for row in &table.rows {
for (i, column) in table.columns.0.iter().enumerate() {
let value = row
.data
.get(&column.name)
.unwrap_or(&serde_json::Value::Null)
.to_string();
column_widths[i] = column_widths[i].max(value.len());
}
}

// Print the header row
let header: Vec<String> = column_names
.iter()
.enumerate()
.map(|(i, &name)| format!("{:<width$}", name, width = column_widths[i]))
.collect();
println!("{}", header.join(" | "));

// Print a separator line
let separator: Vec<String> = column_widths
.iter()
.map(|&width| "-".repeat(width))
.collect();
println!("{}", separator.join("-+-"));

// Print each row of data
for row in &table.rows {
let row_data: Vec<String> = table
.columns
.0
.iter()
.enumerate()
.map(|(i, column)| {
let value = row
.data
.get(&column.name)
.unwrap_or(&serde_json::Value::Null)
.to_string();
format!("{:<width$}", value, width = column_widths[i])
})
.collect();
println!("{}", row_data.join(" | "));
}
}
let view = View::new(self);
view.all_tables();
}

pub fn view_table(&self, table_name: &str) {
if let Some(table) = self.tables.iter().find(|t| t.name == table_name) {
println!("Table: {}", table.name);

if table.columns.0.is_empty() {
println!("No columns defined for table '{}'.", table.name);
return;
}

// Get column names and determine maximum width for each column
let column_names: Vec<&str> = table
.columns
.0
.iter()
.map(|col| col.name.as_str())
.collect();
let mut column_widths: Vec<usize> =
column_names.iter().map(|name| name.len()).collect();

// Adjust column widths based on the content of each row
for row in &table.rows {
for (i, column) in table.columns.0.iter().enumerate() {
let value = row
.data
.get(&column.name)
.unwrap_or(&serde_json::Value::Null)
.to_string();
column_widths[i] = column_widths[i].max(value.len());
}
}

// Print the header row
let header: Vec<String> = column_names
.iter()
.enumerate()
.map(|(i, &name)| format!("{:<width$}", name, width = column_widths[i]))
.collect();
println!("{}", header.join(" | "));

// Print a separator line
let separator: Vec<String> = column_widths
.iter()
.map(|&width| "-".repeat(width))
.collect();
println!("{}", separator.join("-+-"));

// Print each row of data
for row in &table.rows {
let row_data: Vec<String> = table
.columns
.0
.iter()
.enumerate()
.map(|(i, column)| {
let value = row
.data
.get(&column.name)
.unwrap_or(&serde_json::Value::Null)
.to_string();
format!("{:<width$}", value, width = column_widths[i])
})
.collect();
println!("{}", row_data.join(" | "));
}
} else {
println!("Table '{}' not found in the database.", table_name);
}
let view = View::new(self);
view.single_table(table_name);
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/cargobase/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod row;
pub mod table;
pub mod util;
pub mod errors;
pub mod view;

pub use columns::{Column, Columns};
pub use database::Database;
Expand All @@ -13,3 +14,4 @@ pub use row::Row;
pub use table::Table;
pub use util::setup_temp_db;
pub use errors::errors::DatabaseError;
pub use view::View;
63 changes: 6 additions & 57 deletions src/cargobase/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ pub struct Table {
pub(crate) name: String,
pub rows: Vec<Row>,
pub columns: Columns,
// pub(crate) file_name: Option<String>, // reference to the db file_name
}

impl Table {
Expand All @@ -17,15 +16,13 @@ impl Table {
name,
rows: Vec::new(),
columns,
// file_name: None,
}
}

// consider removing this. need to check what it is doing after removing the file name field
pub(crate) fn set_file_name(&mut self, file_name: String) {
// self.file_name = Some(file_name);
println!("File name set to: {}", file_name);
}
// pub(crate) fn set_file_name(&mut self, file_name: String) {
// println!("File name set to: {}", file_name);
// }

pub fn add_row(&mut self, db: &mut Database, data: Value) {
if let Some(table) = db.get_table_mut(&self.name) {
Expand All @@ -45,27 +42,6 @@ impl Table {
println!("Table {} not found", self.name);
}
}

// TODO: Implement this method
//
// fn validate_row(&self, data: &Value) -> Result<(), String> {
// if let Some(obj) = data.as_object() {
// for column in &self.columns.0 {
// if column.required && !obj.contains_key(&column.name) {
// return Err(format!("Missing required column: {}", column.name));
// }
// }
//
// for key in obj.keys() {
// if !self.columns.0.iter().any(|col| col.name == *key) {
// return Err(format!("Invalid column name: {}", key));
// }
// }
// Ok(())
// } else {
// Err("Invalid data format: expected a JSON object.".to_string())
// }
// }
}

#[cfg(test)]
Expand All @@ -84,35 +60,8 @@ mod tests {
#[test]
fn test_table_set_file_name() {
let columns = Columns::new(vec![Column::new("name", true), Column::new("age", false)]);
let mut table = Table::new("users".to_string(), columns.clone());
table.set_file_name("db.json".to_string());
// assert_eq!(table.file_name, Some("db.json".to_string()));
let table = Table::new("users".to_string(), columns.clone());
// table.set_file_name("db.json".to_string());
assert_eq!(table.name, "users");
}
}

// /// Add a new column to the table schema and update existing rows
// pub fn add_column(&mut self, column: Column, db: &mut Database) -> Result<(), String> {
// // Check if the column already exists
// if self.columns.0.iter().any(|col| col.name == column.name) {
// return Err(format!("Column '{}' already exists in table '{}'.", column.name, self.name));
// }
//
// // Add the new column to the schema
// self.columns.0.push(column.clone());
// println!("Column '{}' added to table '{}'.", column.name, self.name);
//
// // Update existing rows by adding the new column with an empty value
// for row in &mut self.rows {
// if !row.data.as_object().unwrap().contains_key(&column.name) {
// row.data[&column.name] = serde_json::Value::Null; // Default to `null` or `Value::String("")`
// }
// }
//
// // Save the updated table back to the database file
// if let Some(file_name) = &self.file_name {
// db.save_to_file().map_err(|e| format!("Failed to save table: {}", e))?;
// }
//
// Ok(())
// }
//
Loading

0 comments on commit aeaba4c

Please sign in to comment.