Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Major Backend Rework #34

Merged
merged 5 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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