WIP: Switch to rusqlite

This commit is contained in:
Joseph Ferano 2023-06-12 21:36:00 +07:00
parent 8393ed610f
commit 076c87c792
6 changed files with 118 additions and 734 deletions

740
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,6 @@ serde_json = "1.0.89"
int-enum = "0.5.0" int-enum = "0.5.0"
thiserror = "1" thiserror = "1"
anyhow = "1" anyhow = "1"
sqlx = { version = "0.6", features = [ "runtime-async-std-native-tls", "sqlite" ] }
async-std = { version = "1", features = [ "attributes" ] }
clap = { version = "4.3.2" , features = [ "derive" ] } clap = { version = "4.3.2" , features = [ "derive" ] }
rusqlite = { version = "0.29", features = [ "bundled" ] }
async-std = { version = "1", features = [ "attributes" ] }

View File

@ -5,6 +5,7 @@ create table if not exists task
id integer primary key autoincrement, id integer primary key autoincrement,
title text not null, title text not null,
description text not null, description text not null,
sort_order integer not null default 0,
column_id integer, column_id integer,
foreign key (column_id) references kb_column(id) foreign key (column_id) references kb_column(id)
); );

View File

@ -1,13 +1,15 @@
// use indexmap::IndexMap; // use indexmap::IndexMap;
// use int_enum::IntEnum; // use int_enum::IntEnum;
use crate::get_all_tasks; // use crate::get_all_tasks;
use rusqlite::Connection;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::SqlitePool;
use std::cmp::min; use std::cmp::min;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use tui_textarea::TextArea; use tui_textarea::TextArea;
use crate::get_all_tasks;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@ -18,7 +20,7 @@ pub struct Column {
pub tasks: Vec<Task>, pub tasks: Vec<Task>,
} }
#[derive(Clone, Default, Deserialize, Serialize, Debug, sqlx::FromRow)] #[derive(Clone, Default, Deserialize, Serialize, Debug)]
pub struct Task { pub struct Task {
pub title: String, pub title: String,
pub description: String, pub description: String,
@ -69,7 +71,7 @@ impl Default for TaskState<'_> {
pub struct State<'a> { pub struct State<'a> {
pub project: Project, pub project: Project,
pub db_pool: SqlitePool, pub db_pool: Connection,
pub quit: bool, pub quit: bool,
pub columns: Vec<Column>, pub columns: Vec<Column>,
pub task_edit_state: Option<TaskState<'a>>, pub task_edit_state: Option<TaskState<'a>>,
@ -77,7 +79,7 @@ pub struct State<'a> {
impl State<'_> { impl State<'_> {
#[must_use] #[must_use]
pub fn new(db_pool: SqlitePool, project: Project) -> Self { pub fn new(db_pool: Connection, project: Project) -> Self {
State { State {
quit: false, quit: false,
task_edit_state: None, task_edit_state: None,
@ -180,8 +182,8 @@ impl Project {
} }
} }
pub async fn load2(pool: &SqlitePool) -> Result<Self, KanbanError> { pub async fn load2(pool: &Connection) -> Result<Self, KanbanError> {
let todos = get_all_tasks(&pool).await.unwrap(); let todos = get_all_tasks(&pool).unwrap();
Ok(Project { Ok(Project {
name: String::from("Kanban Board"), name: String::from("Kanban Board"),

View File

@ -1,30 +1,76 @@
use crate::app::Task; use crate::{Task};
use sqlx::SqlitePool; use rusqlite::{Connection, Result};
pub async fn get_tasks_by_column(pool: &SqlitePool, column_name: &String) -> Option<Vec<Task>> { pub fn get_tasks_by_column(conn: &Connection, column_name: &String) -> Result<Vec<Task>> {
sqlx::query_as!( let mut stmt = conn.prepare(
Task,
r#" r#"
select title, description from task select title, description from task
join kb_column on column_id = kb_column.id join kb_column on column_id = kb_column.id
where kb_column.name = ?1 where kb_column.name = ?1
"#, "#,
column_name )?;
) let mut tasks = Vec::new();
.fetch_all(pool) let rows = stmt.query_map(&[column_name], |row| {
.await Ok(Task {
.ok() title: row.get(0)?,
description: row.get(1)?,
})
})?;
for row in rows {
tasks.push(row?);
}
Ok(tasks)
} }
pub async fn get_all_tasks(pool: &SqlitePool) -> Option<Vec<(String, Vec<Task>)>> { pub fn get_all_tasks(conn: &Connection) -> Result<Vec<(String, Vec<Task>)>> {
let columns = sqlx::query!("select name from kb_column") let mut stmt = conn.prepare("select name from kb_column")?;
.fetch_all(pool) let columns = stmt.query_map((), |row| {
.await Ok(row.get::<usize, String>(0)?)
.unwrap(); })?;
let mut tasks_by_column: Vec<(String, Vec<Task>)> = Vec::with_capacity(columns.len()); let mut tasks_by_column: Vec<(String, Vec<Task>)> = Vec::new();
for col in columns { for col in columns {
let tasks = get_tasks_by_column(pool, &col.name).await.unwrap(); let name = &col?;
tasks_by_column.push((col.name, tasks)); let tasks = get_tasks_by_column(conn, name).unwrap();
tasks_by_column.push((name.to_string(), tasks));
} }
Some(tasks_by_column) Ok(tasks_by_column)
} }
// pub async fn insert_new_task(pool: &SqlitePool, task: &Task, column: &Column) {
// // TODO: You have to add the id to the column
// sqlx::query!("insert into task(title, description, column_id) values (?1, ?2, ?3)", task.title, task.description, 1)
// .execute(pool)
// .await
// .unwrap();
// }
// pub async fn update_task(pool: &SqlitePool, task: &Task) {
// sqlx::query!("update task set title = ?1, description = ?2", task.title, task.description)
// .execute(pool)
// .await
// .unwrap();
// }
// pub async fn move_task_to_column(pool: &SqlitePool, task: &Task, target_column: &Column) {
// // TODO: You have to add the id to the column
// sqlx::query!("update task set column_id = ?1", 1)
// .execute(pool)
// .await
// .unwrap();
// }
// pub async fn move_task_order(pool: &SqlitePool, task: &Task) {
// // TODO: We have to add some kind of ordering mechanism to tasks
// sqlx::query!("update task set column_id = ?1", 1)
// .execute(pool)
// .await
// .unwrap();
// }
// pub async fn delete_task(pool: &SqlitePool, task: &Task) {
// // TODO: We have to add ids to tasks
// sqlx::query!("delete from task where id = ?1", 1)
// .execute(pool)
// .await
// .unwrap();
// }

View File

@ -5,7 +5,7 @@ use crossterm::{
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
}; };
use kanban_tui::{Project, State}; use kanban_tui::{Project, State};
use sqlx::sqlite::SqlitePool; use rusqlite::Connection;
use std::{ use std::{
error::Error, error::Error,
fs::{File, OpenOptions}, fs::{File, OpenOptions},
@ -87,8 +87,9 @@ async fn main() -> anyhow::Result<(), Box<dyn Error>> {
} }
}; };
let db_pool = SqlitePool::connect("sqlite:db.sqlite").await?; let db_pool = Connection::open("db.sqlite")?;
// let project = Project::load(_filepath, &_file)?;
let project = Project::load2(&db_pool).await?; let project = Project::load2(&db_pool).await?;
let mut state = State::new(db_pool, project); let mut state = State::new(db_pool, project);