refactor handlers

pull/3/head
Takayuki Maeda 3 years ago
parent ebc6ff1713
commit 7e0f698c18

@ -10,11 +10,11 @@ pub enum InputMode {
Editing,
}
pub enum FocusType {
Dabatases(bool),
Tables(bool),
Records(bool),
Connections,
pub enum FocusBlock {
DabataseList(bool),
TableList(bool),
RecordTable(bool),
ConnectionList,
}
#[derive(Clone)]
@ -110,7 +110,7 @@ pub struct App {
pub query: String,
pub databases: Vec<Database>,
pub record_table: RecordTable,
pub focus_type: FocusType,
pub focus_type: FocusBlock,
pub user_config: Option<UserConfig>,
pub selected_connection: ListState,
pub selected_database: ListState,
@ -126,7 +126,7 @@ impl Default for App {
query: String::new(),
databases: Vec::new(),
record_table: RecordTable::default(),
focus_type: FocusType::Dabatases(false),
focus_type: FocusBlock::DabataseList(false),
user_config: None,
selected_connection: ListState::default(),
selected_database: ListState::default(),

@ -0,0 +1,34 @@
use crate::app::{App, Database, FocusBlock};
use crate::event::Key;
use crate::utils::get_databases;
use sqlx::mysql::MySqlPool;
pub async fn handler(key: Key, app: &mut App) -> anyhow::Result<()> {
match key {
Key::Char('j') => app.next_connection(),
Key::Char('k') => app.previous_connection(),
Key::Enter => {
app.selected_database.select(Some(0));
app.selected_table.select(Some(0));
if let Some(conn) = app.selected_connection() {
if let Some(pool) = app.pool.as_ref() {
pool.close().await;
}
let pool = MySqlPool::connect(conn.database_url().as_str()).await?;
app.pool = Some(pool);
app.focus_type = FocusBlock::DabataseList(true);
}
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,15 +0,0 @@
use crate::app::{App, FocusType};
use crate::event::Key;
use sqlx::mysql::MySqlPool;
pub async fn handler(_key: Key, app: &mut App) -> anyhow::Result<()> {
if let Some(conn) = app.selected_connection() {
if let Some(pool) = app.pool.as_ref() {
pool.close().await;
}
let pool = MySqlPool::connect(conn.database_url().as_str()).await?;
app.pool = Some(pool);
app.focus_type = FocusType::Dabatases(true);
}
Ok(())
}

@ -1,16 +1,22 @@
use crate::app::{App, Database};
use crate::app::{App, FocusBlock};
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![],
};
pub async fn handler(key: Key, app: &mut App, focused: bool) -> anyhow::Result<()> {
if focused {
match key {
Key::Char('j') => app.next_database(),
Key::Char('k') => app.previous_database(),
Key::Esc => app.focus_type = FocusBlock::DabataseList(false),
_ => (),
}
} else {
match key {
Key::Char('j') => app.focus_type = FocusBlock::TableList(false),
Key::Char('l') => app.focus_type = FocusBlock::RecordTable(false),
Key::Char('c') => app.focus_type = FocusBlock::ConnectionList,
Key::Enter => app.focus_type = FocusBlock::DabataseList(true),
_ => (),
}
}
Ok(())
}

@ -1,31 +0,0 @@
use crate::app::App;
use crate::event::Key;
use crate::utils::convert_column_value_to_string;
use futures::TryStreamExt;
use regex::Regex;
use sqlx::{Column, Executor, Row, TypeInfo};
pub async fn handler(_key: Key, app: &mut App) -> anyhow::Result<()> {
let re = Regex::new(r"from (.+)").unwrap();
let caps = re.captures(app.query.as_str()).unwrap();
let mut rows = sqlx::query(app.query.as_str()).fetch(app.pool.as_ref().unwrap());
let headers =
sqlx::query(format!("desc `{}`", caps.get(1).map_or("hoge", |m| m.as_str())).as_str())
.fetch_all(app.pool.as_ref().unwrap())
.await?
.iter()
.map(|table| table.get(0))
.collect::<Vec<String>>();
let mut records = vec![];
while let Some(row) = rows.try_next().await? {
records.push(
row.columns()
.iter()
.map(|col| convert_column_value_to_string(&row, col))
.collect::<Vec<String>>(),
)
}
app.record_table.headers = headers;
app.record_table.rows = records;
Ok(())
}

@ -1,96 +1,37 @@
pub mod create_connection;
pub mod connection_list;
pub mod database_list;
pub mod execute_query;
pub mod query;
pub mod record_table;
pub mod table_list;
use crate::app::{App, FocusType, InputMode};
use crate::app::{App, FocusBlock, InputMode};
use crate::event::Key;
pub async fn handle_app(key: Key, app: &mut App) -> anyhow::Result<()> {
match app.input_mode {
InputMode::Normal => match key {
Key::Char('e') => {
app.input_mode = InputMode::Editing;
}
Key::Char('c') => {
app.focus_type = FocusType::Connections;
}
Key::Char('l') => app.focus_type = FocusType::Records(false),
Key::Char('h') => app.focus_type = FocusType::Tables(false),
Key::Char('j') => {
if let FocusType::Dabatases(_) = app.focus_type {
app.focus_type = FocusType::Tables(false)
InputMode::Normal => {
match app.focus_type {
FocusBlock::ConnectionList => connection_list::handler(key, app).await?,
FocusBlock::DabataseList(focused) => {
database_list::handler(key, app, focused).await?
}
}
Key::Char('k') => {
if let FocusType::Tables(_) = app.focus_type {
app.focus_type = FocusType::Dabatases(false)
FocusBlock::TableList(focused) => table_list::handler(key, app, focused).await?,
FocusBlock::RecordTable(focused) => {
record_table::handler(key, app, focused).await?
}
}
Key::Right => match app.focus_type {
FocusType::Records(true) => app.record_table.next_column(),
_ => (),
},
Key::Left => match app.focus_type {
FocusType::Records(true) => app.record_table.previous_column(),
_ => (),
},
Key::Up => match app.focus_type {
FocusType::Connections => app.previous_connection(),
FocusType::Records(true) => app.record_table.previous(),
FocusType::Dabatases(true) => app.previous_database(),
FocusType::Tables(true) => match app.selected_database.selected() {
Some(_) => {
app.record_table.column_index = 0;
app.previous_table();
record_table::handler(key, app).await?;
}
None => (),
},
_ => (),
},
Key::Down => match app.focus_type {
FocusType::Connections => app.next_connection(),
FocusType::Records(true) => app.record_table.next(),
FocusType::Dabatases(true) => app.next_database(),
FocusType::Tables(true) => match app.selected_database.selected() {
Some(_) => {
app.record_table.column_index = 0;
app.next_table();
record_table::handler(key, app).await?
}
None => (),
},
_ => (),
},
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?;
}
FocusType::Records(false) => app.focus_type = FocusType::Records(true),
FocusType::Dabatases(false) => app.focus_type = FocusType::Dabatases(true),
FocusType::Tables(false) => app.focus_type = FocusType::Tables(true),
match key {
Key::Char('e') => app.input_mode = InputMode::Editing,
_ => (),
},
_ => {}
},
InputMode::Editing => match key {
Key::Enter => {
app.query = app.input.drain(..).collect();
execute_query::handler(key, app).await?;
}
Key::Char(c) => {
app.input.push(c);
}
}
InputMode::Editing => match key {
Key::Enter => query::handler(key, app).await?,
Key::Char(c) => app.input.push(c),
Key::Backspace => {
app.input.pop();
}
Key::Esc => {
app.input_mode = InputMode::Normal;
}
Key::Esc => app.input_mode = InputMode::Normal,
_ => {}
},
}

@ -0,0 +1,32 @@
use crate::app::App;
use crate::event::Key;
use crate::utils::convert_column_value_to_string;
use futures::TryStreamExt;
use regex::Regex;
use sqlx::Row;
pub async fn handler(_key: Key, app: &mut App) -> anyhow::Result<()> {
app.query = app.input.drain(..).collect();
let re = Regex::new(r"select .+ from (.+)").unwrap();
if let Some(caps) = re.captures(app.query.as_str()) {
let mut rows = sqlx::query(app.query.as_str()).fetch(app.pool.as_ref().unwrap());
let headers = sqlx::query(format!("desc `{}`", caps.get(1).unwrap().as_str()).as_str())
.fetch_all(app.pool.as_ref().unwrap())
.await?
.iter()
.map(|table| table.get(0))
.collect::<Vec<String>>();
let mut records = vec![];
while let Some(row) = rows.try_next().await? {
records.push(
row.columns()
.iter()
.map(|col| convert_column_value_to_string(&row, col))
.collect::<Vec<String>>(),
)
}
app.record_table.headers = headers;
app.record_table.rows = records;
}
Ok(())
}

@ -1,15 +1,22 @@
use crate::app::App;
use crate::app::{App, FocusBlock};
use crate::event::Key;
use crate::utils::get_records;
pub async fn handler(_key: Key, app: &mut App) -> anyhow::Result<()> {
if let Some(database) = app.selected_database() {
if let Some(table) = app.selected_table() {
let (headers, records) =
get_records(database, table, app.pool.as_ref().unwrap()).await?;
app.record_table.state.select(Some(0));
app.record_table.headers = headers;
app.record_table.rows = records;
pub async fn handler(key: Key, app: &mut App, focused: bool) -> anyhow::Result<()> {
if focused {
match key {
Key::Char('h') => app.record_table.previous_column(),
Key::Char('j') => app.record_table.next(),
Key::Char('k') => app.record_table.previous(),
Key::Char('l') => app.record_table.next_column(),
Key::Esc => app.focus_type = FocusBlock::RecordTable(false),
_ => (),
}
} else {
match key {
Key::Char('h') => app.focus_type = FocusBlock::TableList(false),
Key::Char('c') => app.focus_type = FocusBlock::ConnectionList,
Key::Enter => app.focus_type = FocusBlock::RecordTable(true),
_ => (),
}
}
Ok(())

@ -0,0 +1,53 @@
use crate::app::{App, FocusBlock};
use crate::event::Key;
use crate::utils::get_records;
pub async fn handler(key: Key, app: &mut App, focused: bool) -> anyhow::Result<()> {
if focused {
match key {
Key::Char('j') => match app.selected_database.selected() {
Some(_) => {
app.record_table.column_index = 0;
app.next_table();
if let Some(database) = app.selected_database() {
if let Some(table) = app.selected_table() {
let (headers, records) =
get_records(database, table, app.pool.as_ref().unwrap()).await?;
app.record_table.state.select(Some(0));
app.record_table.headers = headers;
app.record_table.rows = records;
}
}
}
None => (),
},
Key::Char('k') => match app.selected_database.selected() {
Some(_) => {
app.record_table.column_index = 0;
app.previous_table();
if let Some(database) = app.selected_database() {
if let Some(table) = app.selected_table() {
let (headers, records) =
get_records(database, table, app.pool.as_ref().unwrap()).await?;
app.record_table.state.select(Some(0));
app.record_table.headers = headers;
app.record_table.rows = records;
}
}
}
None => (),
},
Key::Esc => app.focus_type = FocusBlock::TableList(false),
_ => (),
}
} else {
match key {
Key::Char('k') => app.focus_type = FocusBlock::DabataseList(false),
Key::Char('l') => app.focus_type = FocusBlock::RecordTable(false),
Key::Char('c') => app.focus_type = FocusBlock::ConnectionList,
Key::Enter => app.focus_type = FocusBlock::TableList(true),
_ => (),
}
}
Ok(())
}

@ -5,7 +5,7 @@ mod ui;
mod user_config;
mod utils;
use crate::app::{App, FocusType};
use crate::app::{App, FocusBlock};
use crate::event::{Event, Key};
use crate::handlers::handle_app;
use crossterm::{
@ -31,7 +31,7 @@ async fn main() -> anyhow::Result<()> {
let mut app = App {
user_config,
focus_type: FocusType::Connections,
focus_type: FocusBlock::ConnectionList,
..App::default()
};

@ -1,5 +1,5 @@
use crate::app::InputMode;
use crate::app::{App, FocusType};
use crate::app::{App, FocusBlock};
use tui::{
backend::Backend,
layout::{Constraint, Direction, Layout},
@ -11,7 +11,7 @@ use tui::{
use unicode_width::UnicodeWidthStr;
pub fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App) -> anyhow::Result<()> {
if let FocusType::Connections = app.focus_type {
if let FocusBlock::ConnectionList = app.focus_type {
let percent_x = 60;
let percent_y = 50;
let conns = &app.user_config.as_ref().unwrap().conn;
@ -26,7 +26,7 @@ pub fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App) -> anyhow::Result<(
.block(Block::default().borders(Borders::ALL).title("Connections"))
.highlight_style(Style::default().fg(Color::Green))
.style(match app.focus_type {
FocusType::Connections => Style::default().fg(Color::Green),
FocusBlock::ConnectionList => Style::default().fg(Color::Green),
_ => Style::default(),
});
let popup_layout = Layout::default()
@ -85,8 +85,8 @@ pub fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App) -> anyhow::Result<(
.block(Block::default().borders(Borders::ALL).title("Databases"))
.highlight_style(Style::default().fg(Color::Green))
.style(match app.focus_type {
FocusType::Dabatases(false) => Style::default().fg(Color::Magenta),
FocusType::Dabatases(true) => Style::default().fg(Color::Green),
FocusBlock::DabataseList(false) => Style::default().fg(Color::Magenta),
FocusBlock::DabataseList(true) => Style::default().fg(Color::Green),
_ => Style::default(),
});
f.render_stateful_widget(tasks, left_chunks[0], &mut app.selected_database);
@ -104,8 +104,8 @@ pub fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App) -> anyhow::Result<(
.block(Block::default().borders(Borders::ALL).title("Tables"))
.highlight_style(Style::default().fg(Color::Green))
.style(match app.focus_type {
FocusType::Tables(false) => Style::default().fg(Color::Magenta),
FocusType::Tables(true) => Style::default().fg(Color::Green),
FocusBlock::TableList(false) => Style::default().fg(Color::Magenta),
FocusBlock::TableList(true) => Style::default().fg(Color::Green),
_ => Style::default(),
});
f.render_stateful_widget(tasks, left_chunks[1], &mut app.selected_table);
@ -176,8 +176,8 @@ pub fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App) -> anyhow::Result<(
.block(Block::default().borders(Borders::ALL).title("Records"))
.highlight_style(Style::default().fg(Color::Green))
.style(match app.focus_type {
FocusType::Records(false) => Style::default().fg(Color::Magenta),
FocusType::Records(true) => Style::default().fg(Color::Green),
FocusBlock::RecordTable(false) => Style::default().fg(Color::Magenta),
FocusBlock::RecordTable(true) => Style::default().fg(Color::Green),
_ => Style::default(),
})
.widths(&widths);

Loading…
Cancel
Save