Skip to content

Commit

Permalink
Merge pull request #34 from Piyuuussshhh/fix-ops
Browse files Browse the repository at this point in the history
Major Backend Rework
  • Loading branch information
Piyuuussshhh authored Sep 17, 2024
2 parents 9039211 + e5e4f85 commit f446949
Show file tree
Hide file tree
Showing 14 changed files with 620 additions and 743 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/test_build_on_push_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ name: "test-build-on-push-and-pr"

on:
push:
branches:
- '**' # This makes the workflow run on pushes to any branch.
branches-ignore:
- 'main'
pull_request:
branches-ignore:
- 'main'
branches:
- '**' # This makes the workflow run on pushes to any branch.

# This workflow will build your Tauri app without uploading it anywhere.

Expand Down
172 changes: 126 additions & 46 deletions src-tauri/src/db/init.rs
Original file line number Diff line number Diff line change
@@ -1,63 +1,143 @@
use std::fs;
use std::path::Path;
use std::{fs, path::Path, sync::{Arc, Mutex}};
use chrono::Local;
use rusqlite::{Connection, params, Result as SQLiteResult};

use tauri::AppHandle;
use crate::db::todos::commands::ROOT_GROUP as TODO_ROOT_GROUP;

const DB_NAME: &str = "database.sqlite";
pub type DbConn = Arc<Mutex<Connection>>;

// Initializer struct so that we don't pass AppHandle separately to all helper functions.
pub struct DbInitializer {
pub app_handle: AppHandle,
}
pub fn init(path: &str) -> Connection {
if !db_exists(path) {
create_db(path);
}

// TODO conditional path for diff OS
let db_name = format!("{path}/database.sqlite");

impl DbInitializer {
pub fn new(app_handle: AppHandle) -> Self {
Self { app_handle }
match Connection::open(db_name) {
Ok(conn) => conn,
Err(e) => panic!("[ERROR] {e}"),
}
}

pub fn init(self) -> Self {
if !self.db_file_exists() {
self.create_db_file();
}
// Creation functions.
fn db_exists(path: &str) -> bool {
Path::new(path).exists()
}

self
fn create_db(path: &str) {
let db_dir = Path::new(&path).parent().unwrap();

// If the parent directory does not exist, create it.
if !db_dir.exists() {
fs::create_dir_all(db_dir).unwrap();
}

// Create the database file.
fn create_db_file(&self) {
let db_path = self.get_db_path();
let db_dir = Path::new(&db_path).parent().unwrap();
fs::File::create(path).unwrap();
}

// If the parent directory does not exist, create it.
if !db_dir.exists() {
fs::create_dir_all(db_dir).unwrap();
}
// Setup functions (to be called in main.rs).
pub fn create_tables(conn: &Connection) -> SQLiteResult<()> {
// TODAY
conn.execute(
"CREATE TABLE IF NOT EXISTS today (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
type TEXT NOT NULL,
is_active INTEGER,
parent_group_id INTEGER,
created_at DATE DEFAULT (datetime('now','localtime')) NOT NULL
)",
[],
)?;
// Only add the root group when the table is created for the first time.
conn.execute(
&format!("INSERT INTO today (id, name, type) VALUES (0, '{TODO_ROOT_GROUP}', 'TaskGroup') ON CONFLICT DO NOTHING"),
[],
)?;

// Create the database file.
fs::File::create(db_path).unwrap();
}
// TOMORROW.
conn.execute(
"CREATE TABLE IF NOT EXISTS tomorrow (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
type TEXT NOT NULL,
is_active INTEGER,
parent_group_id INTEGER
)",
[],
)?;
// Only add the root group when the table is created for the first time.
conn.execute(
&format!("INSERT INTO tomorrow (id, name, type) VALUES (0, '{TODO_ROOT_GROUP}', 'TaskGroup') ON CONFLICT DO NOTHING"),
[],
)?;

// Check whether the database file exists.
fn db_file_exists(&self) -> bool {
let db_path = self.get_db_path();
let res = Path::new(&db_path).exists();
conn.execute(
"CREATE TABLE IF NOT EXISTS migration_log (
date TEXT PRIMARY KEY
)",
[],
)?;

return res;
}
Ok(())
}

pub fn migrate_todos(conn: &Connection) -> SQLiteResult<()> {
let today = Local::now().naive_local().date();

let last_migration_date: Option<String> =
match conn
.query_row("SELECT MAX(date) FROM migration_log", [], |row| row.get(0))
{
Ok(latest_date) => latest_date,
Err(err) => panic!("{err}"),
};

if last_migration_date != Some(today.to_string()) {
// Delete completed tasks from today.
conn
.execute("DELETE FROM today WHERE is_active=0", [])?;

let max_id: Option<i64> =
match conn
.query_row("SELECT MAX(id) from today", [], |row| row.get(0))
{
Ok(val) => val,
Err(err) => panic!("{err}"),
};

/// Get the path where the database file should be located.
/// For Linux and macOS only.
pub fn get_db_path(&self) -> String {
let mut res = String::from("");
let app = &self.app_handle;
if let Some(path) = app.path_resolver().app_data_dir() {
if std::env::consts::OS == "windows" {
res = format!("{}\\{DB_NAME}", path.to_string_lossy().into_owned());
} else {
res = format!("{}/{DB_NAME}", path.to_string_lossy().into_owned());
}
}

res
// Update ids of all tasks in tomorrow so that uniqueness is maintained.
conn.execute(
"UPDATE tomorrow SET id=id+(?1) WHERE id!=0",
params![max_id],
)?;

// Update parent_group_ids of all migrated rows.
conn.execute(
"UPDATE tomorrow SET parent_group_id=parent_group_id+(?1) WHERE parent_group_id!=0",
params![max_id],
)?;

// Migrate tasks
conn.execute(
&format!("INSERT INTO today (id, name, type, is_active, parent_group_id)
SELECT id, name, type, is_active, parent_group_id FROM tomorrow WHERE name!='{TODO_ROOT_GROUP}'"),
[],
)?;

// Clear tomorrow's tasks
conn.execute(
&format!("DELETE FROM tomorrow WHERE name!='{TODO_ROOT_GROUP}'"),
[],
)?;
}
// Log the migration
conn.execute(
"INSERT INTO migration_log (date) VALUES (?1) ON CONFLICT DO NOTHING",
params![today.to_string()],
)?;

Ok(())
}
4 changes: 2 additions & 2 deletions src-tauri/src/db/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pub mod ops;
pub mod init;
pub mod init;
pub mod todos;
Loading

0 comments on commit f446949

Please sign in to comment.