forked from extern/nushell
parent
d88d057bf6
commit
75c033e4d1
@ -1,11 +1,11 @@
|
|||||||
use super::super::SQLiteDatabase;
|
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::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, PipelineData, ShellError, Signature, Value,
|
Category, Example, PipelineData, ShellError, Signature, Span, Value,
|
||||||
};
|
};
|
||||||
|
use rusqlite::Connection;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SchemaDb;
|
pub struct SchemaDb;
|
||||||
|
|
||||||
@ -46,25 +46,8 @@ impl Command for SchemaDb {
|
|||||||
let span = call.head;
|
let span = call.head;
|
||||||
|
|
||||||
let sqlite_db = SQLiteDatabase::try_from_pipeline(input, span)?;
|
let sqlite_db = SQLiteDatabase::try_from_pipeline(input, span)?;
|
||||||
let conn = sqlite_db.open_connection().map_err(|e| {
|
let conn = open_sqlite_db_connection(&sqlite_db, span)?;
|
||||||
ShellError::GenericError(
|
let dbs = get_databases_and_tables(&sqlite_db, &conn, span)?;
|
||||||
"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(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
cols.push("db_filename".into());
|
cols.push("db_filename".into());
|
||||||
vals.push(Value::String {
|
vals.push(Value::String {
|
||||||
@ -73,115 +56,15 @@ impl Command for SchemaDb {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for db in dbs {
|
for db in dbs {
|
||||||
let tables = db.tables();
|
let tables = get_database_tables(&db);
|
||||||
let mut table_list: Vec<Value> = vec![];
|
let mut table_list: Vec<Value> = vec![];
|
||||||
let mut table_names = vec![];
|
let mut table_names = vec![];
|
||||||
let mut table_values = vec![];
|
let mut table_values = vec![];
|
||||||
for table in tables {
|
for table in tables {
|
||||||
let columns = sqlite_db.get_columns(&conn, &table).map_err(|e| {
|
let column_info = get_table_columns(&sqlite_db, &conn, &table, span)?;
|
||||||
ShellError::GenericError(
|
let constraint_info = get_table_constraints(&sqlite_db, &conn, &table, span)?;
|
||||||
"Error getting database columns".into(),
|
let foreign_key_info = get_table_foreign_keys(&sqlite_db, &conn, &table, span)?;
|
||||||
e.to_string(),
|
let index_info = get_table_indexes(&sqlite_db, &conn, &table, span)?;
|
||||||
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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
table_names.push(table.name);
|
table_names.push(table.name);
|
||||||
table_values.push(Value::Record {
|
table_values.push(Value::Record {
|
||||||
@ -219,12 +102,15 @@ impl Command for SchemaDb {
|
|||||||
});
|
});
|
||||||
|
|
||||||
cols.push("databases".into());
|
cols.push("databases".into());
|
||||||
|
|
||||||
let mut rcols = vec![];
|
let mut rcols = vec![];
|
||||||
let mut rvals = vec![];
|
let mut rvals = vec![];
|
||||||
rcols.push("name".into());
|
rcols.push("name".into());
|
||||||
rvals.push(Value::string(db.name().to_string(), span));
|
rvals.push(Value::string(db.name().to_string(), span));
|
||||||
|
|
||||||
rcols.push("tables".into());
|
rcols.push("tables".into());
|
||||||
rvals.append(&mut table_list);
|
rvals.append(&mut table_list);
|
||||||
|
|
||||||
vals.push(Value::Record {
|
vals.push(Value::Record {
|
||||||
cols: rcols,
|
cols: rcols,
|
||||||
vals: rvals,
|
vals: rvals,
|
||||||
@ -238,3 +124,177 @@ impl Command for SchemaDb {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn open_sqlite_db_connection(db: &SQLiteDatabase, span: Span) -> Result<Connection, ShellError> {
|
||||||
|
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<Vec<Db>, 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<DbTable> {
|
||||||
|
db.tables()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_table_columns(
|
||||||
|
db: &SQLiteDatabase,
|
||||||
|
conn: &Connection,
|
||||||
|
table: &DbTable,
|
||||||
|
span: Span,
|
||||||
|
) -> Result<Vec<Value>, 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<Vec<Value>, 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<Vec<Value>, 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<Vec<Value>, 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)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user