diff --git a/crates/nu-command/src/database/commands/schema.rs b/crates/nu-command/src/database/commands/schema.rs index 73538cc32..b8261b7ea 100644 --- a/crates/nu-command/src/database/commands/schema.rs +++ b/crates/nu-command/src/database/commands/schema.rs @@ -1,11 +1,11 @@ use super::super::SQLiteDatabase; -use crate::database::values::definitions::db_row::DbRow; +use crate::database::values::definitions::{db::Db, db_row::DbRow, db_table::DbTable}; use nu_protocol::{ ast::Call, engine::{Command, EngineState, Stack}, - Category, Example, PipelineData, ShellError, Signature, Value, + Category, Example, PipelineData, ShellError, Signature, Span, Value, }; - +use rusqlite::Connection; #[derive(Clone)] pub struct SchemaDb; @@ -46,25 +46,8 @@ impl Command for SchemaDb { let span = call.head; let sqlite_db = SQLiteDatabase::try_from_pipeline(input, span)?; - let conn = sqlite_db.open_connection().map_err(|e| { - ShellError::GenericError( - "Error opening file".into(), - e.to_string(), - Some(span), - None, - Vec::new(), - ) - })?; - - let dbs = sqlite_db.get_databases_and_tables(&conn).map_err(|e| { - ShellError::GenericError( - "Error getting databases and tables".into(), - e.to_string(), - Some(span), - None, - Vec::new(), - ) - })?; + let conn = open_sqlite_db_connection(&sqlite_db, span)?; + let dbs = get_databases_and_tables(&sqlite_db, &conn, span)?; cols.push("db_filename".into()); vals.push(Value::String { @@ -73,115 +56,15 @@ impl Command for SchemaDb { }); for db in dbs { - let tables = db.tables(); + let tables = get_database_tables(&db); let mut table_list: Vec = vec![]; let mut table_names = vec![]; let mut table_values = vec![]; for table in tables { - let columns = sqlite_db.get_columns(&conn, &table).map_err(|e| { - ShellError::GenericError( - "Error getting database columns".into(), - e.to_string(), - Some(span), - None, - Vec::new(), - ) - })?; - // a record of column name = column value - let mut column_info = vec![]; - for t in columns { - let mut col_names = vec![]; - let mut col_values = vec![]; - let fields = t.fields(); - let columns = t.columns(); - for (k, v) in fields.iter().zip(columns.iter()) { - col_names.push(k.clone()); - col_values.push(Value::string(v.clone(), span)); - } - column_info.push(Value::Record { - cols: col_names.clone(), - vals: col_values.clone(), - span, - }); - } - - let constraints = sqlite_db.get_constraints(&conn, &table).map_err(|e| { - ShellError::GenericError( - "Error getting DB constraints".into(), - e.to_string(), - Some(span), - None, - Vec::new(), - ) - })?; - let mut constraint_info = vec![]; - for constraint in constraints { - let mut con_cols = vec![]; - let mut con_vals = vec![]; - let fields = constraint.fields(); - let columns = constraint.columns(); - for (k, v) in fields.iter().zip(columns.iter()) { - con_cols.push(k.clone()); - con_vals.push(Value::string(v.clone(), span)); - } - constraint_info.push(Value::Record { - cols: con_cols.clone(), - vals: con_vals.clone(), - span, - }); - } - - let foreign_keys = sqlite_db.get_foreign_keys(&conn, &table).map_err(|e| { - ShellError::GenericError( - "Error getting DB Foreign Keys".into(), - e.to_string(), - Some(span), - None, - Vec::new(), - ) - })?; - let mut foreign_key_info = vec![]; - for fk in foreign_keys { - let mut fk_cols = vec![]; - let mut fk_vals = vec![]; - let fields = fk.fields(); - let columns = fk.columns(); - for (k, v) in fields.iter().zip(columns.iter()) { - fk_cols.push(k.clone()); - fk_vals.push(Value::string(v.clone(), span)); - } - foreign_key_info.push(Value::Record { - cols: fk_cols.clone(), - vals: fk_vals.clone(), - span, - }); - } - - let indexes = sqlite_db.get_indexes(&conn, &table).map_err(|e| { - ShellError::GenericError( - "Error getting DB Indexes".into(), - e.to_string(), - Some(span), - None, - Vec::new(), - ) - })?; - let mut index_info = vec![]; - for index in indexes { - let mut idx_cols = vec![]; - let mut idx_vals = vec![]; - let fields = index.fields(); - let columns = index.columns(); - for (k, v) in fields.iter().zip(columns.iter()) { - idx_cols.push(k.clone()); - idx_vals.push(Value::string(v.clone(), span)); - } - index_info.push(Value::Record { - cols: idx_cols.clone(), - vals: idx_vals.clone(), - span, - }); - } + let column_info = get_table_columns(&sqlite_db, &conn, &table, span)?; + let constraint_info = get_table_constraints(&sqlite_db, &conn, &table, span)?; + let foreign_key_info = get_table_foreign_keys(&sqlite_db, &conn, &table, span)?; + let index_info = get_table_indexes(&sqlite_db, &conn, &table, span)?; table_names.push(table.name); table_values.push(Value::Record { @@ -219,12 +102,15 @@ impl Command for SchemaDb { }); cols.push("databases".into()); + let mut rcols = vec![]; let mut rvals = vec![]; rcols.push("name".into()); rvals.push(Value::string(db.name().to_string(), span)); + rcols.push("tables".into()); rvals.append(&mut table_list); + vals.push(Value::Record { cols: rcols, vals: rvals, @@ -238,3 +124,177 @@ impl Command for SchemaDb { )) } } + +fn open_sqlite_db_connection(db: &SQLiteDatabase, span: Span) -> Result { + db.open_connection().map_err(|e| { + ShellError::GenericError( + "Error opening file".into(), + e.to_string(), + Some(span), + None, + Vec::new(), + ) + }) +} + +fn get_databases_and_tables( + db: &SQLiteDatabase, + conn: &Connection, + span: Span, +) -> Result, ShellError> { + db.get_databases_and_tables(conn).map_err(|e| { + ShellError::GenericError( + "Error getting databases and tables".into(), + e.to_string(), + Some(span), + None, + Vec::new(), + ) + }) +} + +fn get_database_tables(db: &Db) -> Vec { + db.tables() +} + +fn get_table_columns( + db: &SQLiteDatabase, + conn: &Connection, + table: &DbTable, + span: Span, +) -> Result, ShellError> { + let columns = db.get_columns(conn, table).map_err(|e| { + ShellError::GenericError( + "Error getting database columns".into(), + e.to_string(), + Some(span), + None, + Vec::new(), + ) + })?; + + // a record of column name = column value + let mut column_info = vec![]; + for t in columns { + let mut col_names = vec![]; + let mut col_values = vec![]; + let fields = t.fields(); + let columns = t.columns(); + for (k, v) in fields.iter().zip(columns.iter()) { + col_names.push(k.clone()); + col_values.push(Value::string(v.clone(), span)); + } + column_info.push(Value::Record { + cols: col_names.clone(), + vals: col_values.clone(), + span, + }); + } + + Ok(column_info) +} + +fn get_table_constraints( + db: &SQLiteDatabase, + conn: &Connection, + table: &DbTable, + span: Span, +) -> Result, ShellError> { + let constraints = db.get_constraints(conn, table).map_err(|e| { + ShellError::GenericError( + "Error getting DB constraints".into(), + e.to_string(), + Some(span), + None, + Vec::new(), + ) + })?; + let mut constraint_info = vec![]; + for constraint in constraints { + let mut con_cols = vec![]; + let mut con_vals = vec![]; + let fields = constraint.fields(); + let columns = constraint.columns(); + for (k, v) in fields.iter().zip(columns.iter()) { + con_cols.push(k.clone()); + con_vals.push(Value::string(v.clone(), span)); + } + constraint_info.push(Value::Record { + cols: con_cols.clone(), + vals: con_vals.clone(), + span, + }); + } + + Ok(constraint_info) +} + +fn get_table_foreign_keys( + db: &SQLiteDatabase, + conn: &Connection, + table: &DbTable, + span: Span, +) -> Result, ShellError> { + let foreign_keys = db.get_foreign_keys(conn, table).map_err(|e| { + ShellError::GenericError( + "Error getting DB Foreign Keys".into(), + e.to_string(), + Some(span), + None, + Vec::new(), + ) + })?; + let mut foreign_key_info = vec![]; + for fk in foreign_keys { + let mut fk_cols = vec![]; + let mut fk_vals = vec![]; + let fields = fk.fields(); + let columns = fk.columns(); + for (k, v) in fields.iter().zip(columns.iter()) { + fk_cols.push(k.clone()); + fk_vals.push(Value::string(v.clone(), span)); + } + foreign_key_info.push(Value::Record { + cols: fk_cols.clone(), + vals: fk_vals.clone(), + span, + }); + } + + Ok(foreign_key_info) +} + +fn get_table_indexes( + db: &SQLiteDatabase, + conn: &Connection, + table: &DbTable, + span: Span, +) -> Result, ShellError> { + let indexes = db.get_indexes(conn, table).map_err(|e| { + ShellError::GenericError( + "Error getting DB Indexes".into(), + e.to_string(), + Some(span), + None, + Vec::new(), + ) + })?; + let mut index_info = vec![]; + for index in indexes { + let mut idx_cols = vec![]; + let mut idx_vals = vec![]; + let fields = index.fields(); + let columns = index.columns(); + for (k, v) in fields.iter().zip(columns.iter()) { + idx_cols.push(k.clone()); + idx_vals.push(Value::string(v.clone(), span)); + } + index_info.push(Value::Record { + cols: idx_cols.clone(), + vals: idx_vals.clone(), + span, + }); + } + + Ok(index_info) +}