fix layout

pull/3/head
Takayuki Maeda 3 years ago
parent fc33179427
commit b8e930b186

@ -19,14 +19,20 @@ pub enum FocusType {
#[derive(Clone)]
pub struct Database {
pub selected_table: ListState,
pub name: String,
pub tables: Vec<Table>,
}
#[derive(Clone)]
#[derive(sqlx::FromRow, Debug, Clone)]
pub struct Table {
#[sqlx(rename = "Name")]
pub name: String,
#[sqlx(rename = "Create_time")]
pub create_time: chrono::DateTime<chrono::Utc>,
#[sqlx(rename = "Update_time")]
pub update_time: Option<chrono::DateTime<chrono::Utc>>,
#[sqlx(rename = "Engine")]
pub engine: String,
}
pub struct RecordTable {
@ -92,51 +98,23 @@ impl RecordTable {
impl Database {
pub async fn new(name: String, pool: &MySqlPool) -> anyhow::Result<Self> {
Ok(Self {
selected_table: ListState::default(),
name: name.clone(),
tables: get_tables(name, pool).await?,
})
}
pub fn next(&mut self) {
let i = match self.selected_table.selected() {
Some(i) => {
if i >= self.tables.len() - 1 {
0
} else {
i + 1
}
}
None => 0,
};
self.selected_table.select(Some(i));
}
pub fn previous(&mut self) {
let i = match self.selected_table.selected() {
Some(i) => {
if i == 0 {
self.tables.len() - 1
} else {
i - 1
}
}
None => 0,
};
self.selected_table.select(Some(i));
}
}
pub struct App {
pub input: String,
pub input_mode: InputMode,
pub messages: Vec<Vec<String>>,
pub selected_database: ListState,
pub databases: Vec<Database>,
pub record_table: RecordTable,
pub focus_type: FocusType,
pub user_config: Option<UserConfig>,
pub selected_connection: ListState,
pub selected_database: ListState,
pub selected_table: ListState,
pub pool: Option<MySqlPool>,
}
@ -146,18 +124,47 @@ impl Default for App {
input: String::new(),
input_mode: InputMode::Normal,
messages: Vec::new(),
selected_database: ListState::default(),
databases: Vec::new(),
record_table: RecordTable::default(),
focus_type: FocusType::Dabatases(false),
user_config: None,
selected_connection: ListState::default(),
selected_database: ListState::default(),
selected_table: ListState::default(),
pool: None,
}
}
}
impl App {
pub fn next_table(&mut self) {
let i = match self.selected_table.selected() {
Some(i) => {
if i >= self.selected_database().unwrap().tables.len() - 1 {
0
} else {
i + 1
}
}
None => 0,
};
self.selected_table.select(Some(i));
}
pub fn previous_table(&mut self) {
let i = match self.selected_table.selected() {
Some(i) => {
if i == 0 {
self.selected_database().unwrap().tables.len() - 1
} else {
i - 1
}
}
None => 0,
};
self.selected_table.select(Some(i));
}
pub fn next_database(&mut self) {
let i = match self.selected_database.selected() {
Some(i) => {
@ -169,6 +176,7 @@ impl App {
}
None => 0,
};
self.selected_table.select(Some(0));
self.selected_database.select(Some(i));
}
@ -183,6 +191,7 @@ impl App {
}
None => 0,
};
self.selected_table.select(Some(0));
self.selected_database.select(Some(i));
}
@ -229,9 +238,9 @@ impl App {
}
pub fn selected_table(&self) -> Option<&Table> {
match self.selected_database() {
Some(db) => match db.selected_table.selected() {
Some(i) => db.tables.get(i),
match self.selected_table.selected() {
Some(i) => match self.selected_database() {
Some(db) => db.tables.get(i),
None => None,
},
None => None,

@ -0,0 +1,16 @@
use crate::app::{App, Database};
use crate::event::Key;
use crate::utils::get_databases;
pub async fn handler(_key: Key, app: &mut App) -> anyhow::Result<()> {
app.databases = match app.selected_connection() {
Some(conn) => match &conn.database {
Some(database) => {
vec![Database::new(database.clone(), app.pool.as_ref().unwrap()).await?]
}
None => get_databases(app.pool.as_ref().unwrap()).await?,
},
None => vec![],
};
Ok(())
}

@ -1,5 +1,6 @@
pub mod create_connection;
pub mod database_list;
pub mod execute_query;
pub mod record_table;
use crate::app::{App, FocusType, InputMode};
@ -39,9 +40,9 @@ pub async fn handle_app(key: Key, app: &mut App) -> anyhow::Result<()> {
FocusType::Records(true) => app.record_table.previous(),
FocusType::Dabatases(true) => app.previous_database(),
FocusType::Tables(true) => match app.selected_database.selected() {
Some(index) => {
Some(_) => {
app.record_table.column_index = 0;
app.databases[index].previous();
app.previous_table();
record_table::handler(key, app).await?;
}
None => (),
@ -53,9 +54,9 @@ pub async fn handle_app(key: Key, app: &mut App) -> anyhow::Result<()> {
FocusType::Records(true) => app.record_table.next(),
FocusType::Dabatases(true) => app.next_database(),
FocusType::Tables(true) => match app.selected_database.selected() {
Some(index) => {
Some(_) => {
app.record_table.column_index = 0;
app.databases[index].next();
app.next_table();
record_table::handler(key, app).await?
}
None => (),
@ -65,6 +66,7 @@ pub async fn handle_app(key: Key, app: &mut App) -> anyhow::Result<()> {
Key::Enter => match app.focus_type {
FocusType::Connections => {
app.selected_database.select(Some(0));
app.selected_table.select(Some(0));
create_connection::handler(key, app).await?;
database_list::handler(key, app).await?;
}

@ -58,15 +58,20 @@ pub fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App) -> anyhow::Result<(
}
let main_chunks = Layout::default()
.direction(Direction::Vertical)
.margin(2)
.constraints([Constraint::Percentage(15), Constraint::Percentage(85)])
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(15), Constraint::Percentage(85)])
.split(f.size());
let left_chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Percentage(30), Constraint::Percentage(70)].as_ref())
.constraints(
[
Constraint::Length(9),
Constraint::Min(8),
Constraint::Length(7),
]
.as_ref(),
)
.split(main_chunks[0]);
let databases: Vec<ListItem> = app
.databases
@ -103,15 +108,33 @@ pub fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App) -> anyhow::Result<(
FocusType::Tables(true) => Style::default().fg(Color::Green),
_ => Style::default(),
});
f.render_stateful_widget(
tasks,
left_chunks[1],
&mut app.databases[app.selected_database.selected().unwrap_or(0)].selected_table,
);
f.render_stateful_widget(tasks, left_chunks[1], &mut app.selected_table);
let info: Vec<ListItem> = vec![
format!(
"created: {}",
app.selected_table().unwrap().create_time.to_string()
),
// format!(
// "updated: {}",
// app.selected_table().unwrap().update_time.to_string()
// ),
format!("rows: {}", app.record_table.rows.len()),
]
.iter()
.map(|i| {
ListItem::new(vec![Spans::from(Span::raw(i.to_string()))])
.style(Style::default().fg(Color::White))
})
.collect();
let tasks = List::new(info)
.block(Block::default().borders(Borders::ALL))
.highlight_style(Style::default().fg(Color::Green));
f.render_widget(tasks, left_chunks[2]);
let right_chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Length(3), Constraint::Min(1)].as_ref())
.constraints([Constraint::Length(3), Constraint::Length(5)].as_ref())
.split(main_chunks[1]);
let input = Paragraph::new(app.input.as_ref())

@ -5,7 +5,7 @@ use sqlx::mysql::MySqlPool;
use sqlx::{Column, Executor, Row, TypeInfo};
pub async fn get_databases(pool: &MySqlPool) -> anyhow::Result<Vec<Database>> {
let databases = sqlx::query("show databases")
let databases = sqlx::query("SHOW DATABASES")
.fetch_all(pool)
.await?
.iter()
@ -19,12 +19,10 @@ pub async fn get_databases(pool: &MySqlPool) -> anyhow::Result<Vec<Database>> {
}
pub async fn get_tables(database: String, pool: &MySqlPool) -> anyhow::Result<Vec<Table>> {
let tables = sqlx::query(format!("show tables from `{}`", database).as_str())
.fetch_all(pool)
.await?
.iter()
.map(|table| Table { name: table.get(0) })
.collect::<Vec<Table>>();
let tables =
sqlx::query_as::<_, Table>(format!("SHOW TABLE STATUS FROM `{}`", database).as_str())
.fetch_all(pool)
.await?;
Ok(tables)
}
@ -33,9 +31,7 @@ pub async fn get_records(
table: &Table,
pool: &MySqlPool,
) -> anyhow::Result<(Vec<String>, Vec<Vec<String>>)> {
pool.execute(format!("use `{}`", database.name).as_str())
.await?;
let table_name = format!("SELECT * FROM `{}`", table.name);
let table_name = format!("SELECT * FROM `{}`.`{}`", database.name, table.name);
let mut rows = sqlx::query(table_name.as_str()).fetch(pool);
let headers = sqlx::query(format!("desc `{}`", table.name).as_str())
.fetch_all(pool)

Loading…
Cancel
Save