You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gobang/src/app.rs

361 lines
9.3 KiB
Rust

use crate::{
user_config::{Connection, UserConfig},
utils::get_tables,
};
use sqlx::mysql::MySqlPool;
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
use tui::widgets::{ListState, TableState};
use unicode_width::UnicodeWidthStr;
3 years ago
#[derive(Debug, Clone, Copy, EnumIter)]
pub enum Tab {
Records,
Structure,
}
impl std::fmt::Display for Tab {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl Tab {
pub fn names() -> Vec<String> {
Self::iter().map(|tab| tab.to_string()).collect()
}
}
pub enum FocusBlock {
DabataseList(bool),
TableList(bool),
RecordTable(bool),
ConnectionList,
Query(bool),
}
#[derive(Clone)]
pub struct Database {
pub name: String,
pub tables: Vec<Table>,
}
#[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: Option<String>,
}
#[derive(sqlx::FromRow, Debug, Clone)]
pub struct Column {
#[sqlx(rename = "Field")]
pub field: String,
#[sqlx(rename = "Type")]
pub r#type: String,
#[sqlx(rename = "Collation")]
pub collation: String,
#[sqlx(rename = "Null")]
pub null: String,
}
pub struct RecordTable {
pub state: TableState,
pub headers: Vec<String>,
pub rows: Vec<Vec<String>>,
pub column_index: usize,
}
impl Default for RecordTable {
fn default() -> Self {
Self {
state: TableState::default(),
headers: vec![],
rows: vec![],
column_index: 0,
}
}
}
impl RecordTable {
pub fn next(&mut self) {
let i = match self.state.selected() {
Some(i) => {
if i >= self.rows.len() - 1 {
0
} else {
i + 1
}
}
None => 0,
};
self.state.select(Some(i));
}
pub fn previous(&mut self) {
let i = match self.state.selected() {
Some(i) => {
if i == 0 {
self.rows.len() - 1
} else {
i - 1
}
}
None => 0,
};
self.state.select(Some(i));
}
pub fn next_column(&mut self) {
if self.headers.len() > 9 && self.column_index < self.headers.len() - 9 {
self.column_index += 1
}
}
pub fn previous_column(&mut self) {
if self.column_index > 0 {
self.column_index -= 1
}
}
pub fn headers(&self) -> Vec<String> {
let mut headers = self.headers[self.column_index..].to_vec();
headers.insert(0, "".to_string());
headers
}
pub fn rows(&self) -> Vec<Vec<String>> {
let mut rows = self
.rows
.iter()
.map(|row| row[self.column_index..].to_vec())
.collect::<Vec<Vec<String>>>();
for (index, row) in rows.iter_mut().enumerate() {
row.insert(0, (index + 1).to_string())
}
rows
}
}
impl Database {
pub async fn new(name: String, pool: &MySqlPool) -> anyhow::Result<Self> {
Ok(Self {
name: name.clone(),
tables: get_tables(name, pool).await?,
})
}
}
3 years ago
pub struct App {
pub input: String,
pub input_cursor_x: u16,
pub query: String,
pub databases: Vec<Database>,
pub record_table: RecordTable,
pub structure_table: RecordTable,
pub focus_block: FocusBlock,
pub selected_tab: Tab,
pub user_config: Option<UserConfig>,
pub selected_connection: ListState,
pub selected_database: ListState,
pub selected_table: ListState,
pub pool: Option<MySqlPool>,
pub error: Option<String>,
3 years ago
}
impl Default for App {
fn default() -> App {
App {
input: String::new(),
input_cursor_x: 0,
query: String::new(),
databases: Vec::new(),
record_table: RecordTable::default(),
structure_table: RecordTable::default(),
focus_block: FocusBlock::DabataseList(false),
selected_tab: Tab::Records,
user_config: None,
selected_connection: ListState::default(),
selected_database: ListState::default(),
selected_table: ListState::default(),
pool: None,
error: None,
3 years ago
}
}
}
impl App {
pub fn next_tab(&mut self) {
self.selected_tab = match self.selected_tab {
Tab::Records => Tab::Structure,
Tab::Structure => Tab::Records,
}
}
pub fn previous_tab(&mut self) {
self.selected_tab = match self.selected_tab {
Tab::Records => Tab::Structure,
Tab::Structure => Tab::Records,
}
}
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));
3 years ago
}
pub fn next_database(&mut self) {
let i = match self.selected_database.selected() {
Some(i) => {
if i >= self.databases.len() - 1 {
0
} else {
i + 1
}
}
None => 0,
};
self.selected_table.select(Some(0));
self.selected_database.select(Some(i));
}
pub fn previous_database(&mut self) {
let i = match self.selected_database.selected() {
Some(i) => {
if i == 0 {
self.databases.len() - 1
} else {
i - 1
}
}
None => 0,
};
self.selected_table.select(Some(0));
self.selected_database.select(Some(i));
}
pub fn next_connection(&mut self) {
if let Some(config) = &self.user_config {
let i = match self.selected_connection.selected() {
Some(i) => {
if i >= config.conn.len() - 1 {
0
} else {
i + 1
}
}
None => 0,
};
self.selected_connection.select(Some(i));
}
}
pub fn previous_connection(&mut self) {
if let Some(config) = &self.user_config {
let i = match self.selected_connection.selected() {
Some(i) => {
if i == 0 {
config.conn.len() - 1
} else {
i - 1
}
}
None => 0,
};
self.selected_connection.select(Some(i));
}
}
pub fn increment_input_cursor_x(&mut self) {
if self.input_cursor_x > 0 {
self.input_cursor_x -= 1;
}
}
pub fn decrement_input_cursor_x(&mut self) {
if self.input_cursor_x < self.input.width() as u16 {
self.input_cursor_x += 1;
}
}
pub fn selected_database(&self) -> Option<&Database> {
match self.selected_database.selected() {
Some(i) => self.databases.get(i),
None => None,
}
}
pub fn selected_table(&self) -> Option<&Table> {
match self.selected_table.selected() {
Some(i) => match self.selected_database() {
Some(db) => db.tables.get(i),
None => None,
},
None => None,
}
}
pub fn selected_connection(&self) -> Option<&Connection> {
match &self.user_config {
Some(config) => match self.selected_connection.selected() {
Some(i) => config.conn.get(i),
None => None,
},
None => None,
}
}
pub fn table_status(&self) -> Vec<String> {
if let Some(table) = self.selected_table() {
return vec![
format!("created: {}", table.create_time.to_string()),
format!(
"updated: {}",
table
.update_time
.map(|time| time.to_string())
.unwrap_or_default()
),
format!(
"engine: {}",
table
.engine
.as_ref()
.map(|engine| engine.to_string())
.unwrap_or_default()
),
format!("rows: {}", self.record_table.rows.len()),
];
}
Vec::new()
}
3 years ago
}