diff --git a/.config/config.kdl b/.config/config.kdl index 47bcb93..3d9b35c 100644 --- a/.config/config.kdl +++ b/.config/config.kdl @@ -1,5 +1,6 @@ keymap { + Home { q Quit // Quit the application Quit // Another way to quit diff --git a/Cargo.lock b/Cargo.lock index 02be5ea..8518bd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -806,6 +806,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.0", +] + [[package]] name = "chrono" version = "0.4.44" @@ -994,6 +1005,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -1183,7 +1203,9 @@ dependencies = [ name = "db" version = "0.1.0" dependencies = [ + "anyhow", "migration", + "rand 0.10.0", "sea-orm", "thiserror 2.0.18", "tokio", @@ -1744,6 +1766,7 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", + "rand_core 0.10.0", "wasip2", "wasip3", ] @@ -3243,6 +3266,8 @@ name = "migration" version = "0.1.0" dependencies = [ "async-std", + "nanoid", + "sea-orm", "sea-orm-migration", ] @@ -3274,6 +3299,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "nanoid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" +dependencies = [ + "rand 0.8.5", +] + [[package]] name = "nix" version = "0.29.0" @@ -3923,6 +3957,17 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.0", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -3961,6 +4006,12 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + [[package]] name = "ratatui" version = "0.30.0" @@ -4510,7 +4561,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -4531,7 +4582,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -4542,7 +4593,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.11.2", ] diff --git a/crates/db/Cargo.toml b/crates/db/Cargo.toml index 58cdc89..e593e92 100644 --- a/crates/db/Cargo.toml +++ b/crates/db/Cargo.toml @@ -20,6 +20,10 @@ migration = {path="migration"} [dev-dependencies] tokio = {workspace = true} +anyhow = "1.0.102" +rand = "0.10.0" + [lints] -workspace = true +# a lot of autogenerated things, lints arent very useful +# workspace = true diff --git a/crates/db/migration/Cargo.toml b/crates/db/migration/Cargo.toml index 6a70f99..f5d4438 100644 --- a/crates/db/migration/Cargo.toml +++ b/crates/db/migration/Cargo.toml @@ -10,6 +10,8 @@ path = "src/lib.rs" [dependencies] async-std = { version = "1", features = ["attributes", "tokio1"] } +nanoid = "0.4.0" +sea-orm = "2.0.0-rc" [dependencies.sea-orm-migration] version = "2.0.0-rc" diff --git a/crates/db/migration/src/lib.rs b/crates/db/migration/src/lib.rs index 34f7c89..0f7e7cb 100644 --- a/crates/db/migration/src/lib.rs +++ b/crates/db/migration/src/lib.rs @@ -1,5 +1,7 @@ pub use sea_orm_migration::prelude::*; +pub mod types; + mod m20260318_233726_group_table; mod m20260319_002245_task_table; diff --git a/crates/db/migration/src/m20260318_233726_group_table.rs b/crates/db/migration/src/m20260318_233726_group_table.rs index 915db60..3348b7d 100644 --- a/crates/db/migration/src/m20260318_233726_group_table.rs +++ b/crates/db/migration/src/m20260318_233726_group_table.rs @@ -1,5 +1,7 @@ use sea_orm_migration::{prelude::*, schema::*}; +use crate::types::{NANO_ID_LEN, NanoId, Priority}; + #[derive(DeriveMigrationName)] pub struct Migration; @@ -12,12 +14,22 @@ impl MigrationTrait for Migration { .table(Group::Table) .if_not_exists() .col(pk_auto(Group::Id)) - .col(string(Group::NanoId).unique_key().not_null()) + .col( + string(Group::NanoId) + .string_len(NANO_ID_LEN as u32) + .unique_key() + .not_null() + .default(NanoId::default().0), + ) .col(string(Group::Name).not_null()) //Note: Color is a hex color with the leading # .col(string(Group::Color).not_null()) .col(string(Group::DescriptionPath).not_null()) - .col(integer(Group::Priority).not_null().default(0)) + .col( + string(Group::Priority) + .not_null() + .default(Priority::default().to_string()), + ) .col(timestamp(Group::CreatedAt).default(Expr::current_timestamp())) .col(timestamp(Group::ModifiedAt).default(Expr::current_timestamp())) .col(string_null(Group::ParentGroupId)) diff --git a/crates/db/migration/src/m20260319_002245_task_table.rs b/crates/db/migration/src/m20260319_002245_task_table.rs index 7d14781..e46b657 100644 --- a/crates/db/migration/src/m20260319_002245_task_table.rs +++ b/crates/db/migration/src/m20260319_002245_task_table.rs @@ -1,6 +1,9 @@ use sea_orm_migration::{prelude::*, schema::*}; -use crate::m20260318_233726_group_table::Group; +use crate::{ + m20260318_233726_group_table::Group, + types::{NANO_ID_LEN, NanoId, Priority}, +}; #[derive(DeriveMigrationName)] pub struct Migration; @@ -14,14 +17,24 @@ impl MigrationTrait for Migration { .table(Task::Table) .if_not_exists() .col(pk_auto(Task::Id)) - .col(string(Task::NanoId).unique_key().not_null()) + .col( + string(Task::NanoId) + .string_len(NANO_ID_LEN as u32) + .unique_key() + .not_null() + .default(NanoId::default().0), + ) .col(string(Task::Name).not_null()) .col(string(Task::DescriptionPath).not_null()) - .col(integer(Task::Priority).not_null().default(0)) + .col( + string(Task::Priority) + .not_null() + .default(Priority::default().to_string()), + ) .col(timestamp(Task::Due).null()) .col(timestamp(Task::CreatedAt).default(Expr::current_timestamp())) .col(timestamp(Task::ModifiedAt).default(Expr::current_timestamp())) - .col(string_null(Task::GroupId)) + .col(string(Task::GroupId).not_null()) .foreign_key( ForeignKey::create() .name("fk_task_group_id") // unique constraint name diff --git a/crates/db/migration/src/types/mod.rs b/crates/db/migration/src/types/mod.rs new file mode 100644 index 0000000..f0c74bb --- /dev/null +++ b/crates/db/migration/src/types/mod.rs @@ -0,0 +1,6 @@ +mod priority; +pub use priority::Priority; + +mod nano_id; +pub(crate) use nano_id::NANO_ID_LEN; +pub use nano_id::NanoId; diff --git a/crates/db/migration/src/types/nano_id.rs b/crates/db/migration/src/types/nano_id.rs new file mode 100644 index 0000000..0ddb681 --- /dev/null +++ b/crates/db/migration/src/types/nano_id.rs @@ -0,0 +1,46 @@ +use nanoid::nanoid; +use sea_orm::DeriveValueType; + +#[derive(Clone, Debug, PartialEq, Eq, DeriveValueType)] +#[sea_orm(value_type = "String")] +pub struct NanoId(pub(crate) String); + +const ALPHABET: [char; 26] = [ + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z', +]; + +pub const NANO_ID_LEN: usize = 6; + +impl Default for NanoId { + fn default() -> Self { + Self(nanoid!(NANO_ID_LEN, &ALPHABET)) + } +} + +#[derive(Debug)] +pub struct NanoIdParseError { + bad: String, +} + +impl std::error::Error for NanoIdParseError {} + +impl std::fmt::Display for NanoIdParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} is not a valid NanoId!", self.bad) + } +} + +impl std::fmt::Display for NanoId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl std::str::FromStr for NanoId { + type Err = NanoIdParseError; + + fn from_str(s: &str) -> Result { + Ok(Self(s.to_owned())) + } +} diff --git a/crates/db/migration/src/types/priority.rs b/crates/db/migration/src/types/priority.rs new file mode 100644 index 0000000..7a05fce --- /dev/null +++ b/crates/db/migration/src/types/priority.rs @@ -0,0 +1,56 @@ +use sea_orm::DeriveValueType; + +#[derive(Clone, Debug, PartialEq, Eq, DeriveValueType, Default)] +#[sea_orm(value_type = "String")] +pub enum Priority { + Asap, + High, + #[default] + Medium, + Low, + Far, +} + +#[derive(Debug)] +pub struct PriorityParseError { + bad: String, +} + +impl std::error::Error for PriorityParseError {} + +impl std::fmt::Display for PriorityParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} is not a valid Priority!", self.bad) + } +} + +impl std::fmt::Display for Priority { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let str = match self { + Priority::Asap => "ASAP", + Priority::High => "High", + Priority::Medium => "Medium", + Priority::Low => "Low", + Priority::Far => "Far", + }; + + write!(f, "{str}") + } +} + +impl std::str::FromStr for Priority { + type Err = PriorityParseError; + + fn from_str(s: &str) -> Result { + let v = match s { + "ASAP" => Self::Asap, + "High" => Self::High, + "Medium" => Priority::Medium, + "Low" => Self::Low, + "Far" => Self::Far, + _ => return Err(PriorityParseError { bad: s.to_owned() }), + }; + + Ok(v) + } +} diff --git a/crates/db/src/entity/group.rs b/crates/db/src/entity/group.rs index 4bc9ffc..d6a1dd8 100644 --- a/crates/db/src/entity/group.rs +++ b/crates/db/src/entity/group.rs @@ -1,41 +1,34 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0 use sea_orm::entity::prelude::*; +use migration::types::*; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] #[sea_orm(table_name = "group")] pub struct Model { #[sea_orm(primary_key)] - pub id: i32, + pub id: i64, #[sea_orm(unique)] - pub nano_id: String, + pub nano_id: NanoId, pub name: String, pub color: String, pub description_path: String, - pub priority: i32, + pub priority: Priority, pub created_at: DateTimeUtc, pub modified_at: DateTimeUtc, - pub parent_group_id: Option, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { + pub parent_group_id: Option, #[sea_orm( - belongs_to = "Entity", - from = "Column::ParentGroupId", - to = "Column::NanoId", + self_ref, + relation_enum = "SelfRef", + from = "parent_group_id", + to = "nano_id", on_update = "Cascade", on_delete = "Cascade" )] - SelfRef, - #[sea_orm(has_many = "super::task::Entity")] - Task, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Task.def() - } + pub group: HasOne, + #[sea_orm(has_many)] + pub tasks: HasMany, } impl ActiveModelBehavior for ActiveModel {} diff --git a/crates/db/src/entity/mod.rs b/crates/db/src/entity/mod.rs index 2d5756b..cf2cd5c 100644 --- a/crates/db/src/entity/mod.rs +++ b/crates/db/src/entity/mod.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0 pub mod prelude; diff --git a/crates/db/src/entity/prelude.rs b/crates/db/src/entity/prelude.rs index 251d363..963c3a8 100644 --- a/crates/db/src/entity/prelude.rs +++ b/crates/db/src/entity/prelude.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0 pub use super::group::Entity as Group; pub use super::task::Entity as Task; diff --git a/crates/db/src/entity/task.rs b/crates/db/src/entity/task.rs index 4f55ed1..d417d50 100644 --- a/crates/db/src/entity/task.rs +++ b/crates/db/src/entity/task.rs @@ -1,39 +1,31 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0 +use migration::types::*; use sea_orm::entity::prelude::*; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] #[sea_orm(table_name = "task")] pub struct Model { #[sea_orm(primary_key)] - pub id: i32, + pub id: i64, #[sea_orm(unique)] - pub nano_id: String, + pub nano_id: NanoId, pub name: String, pub description_path: String, - pub priority: i32, + pub priority: Priority, pub due: Option, pub created_at: DateTimeUtc, pub modified_at: DateTimeUtc, - pub group_id: Option, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { + pub group_id: NanoId, #[sea_orm( - belongs_to = "super::group::Entity", - from = "Column::GroupId", - to = "super::group::Column::NanoId", + belongs_to, + from = "group_id", + to = "nano_id", on_update = "Cascade", on_delete = "Cascade" )] - Group, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Group.def() - } + pub group: HasOne, } impl ActiveModelBehavior for ActiveModel {} diff --git a/crates/db/src/lib.rs b/crates/db/src/lib.rs index a3c75fe..ee60963 100644 --- a/crates/db/src/lib.rs +++ b/crates/db/src/lib.rs @@ -1,7 +1,7 @@ //! The database abstraction for the different actions `Filaments` requires //! from a database service. -use std::path::Path; +use std::path::PathBuf; use migration::{Migrator, MigratorTrait}; use sea_orm::{Database, DatabaseConnection}; @@ -13,28 +13,41 @@ use crate::errors::{DbError, DbResult}; mod errors; /// Database entities -mod entity; +pub mod entity; + +pub use sea_orm::ActiveValue; #[expect(unused_imports)] pub use errors::*; /// Database struct -#[expect(dead_code)] #[derive(Debug)] -struct Db { +pub struct Db { conn: DatabaseConnection, } +impl AsRef for Db { + fn as_ref(&self) -> &DatabaseConnection { + &self.conn + } +} + impl Db { - async fn connect(path: &Path) -> DbResult { - let connection_string = dbg! {format!( + /// Connects to the database to the database at `path`. + /// + /// # Errors + /// Will error if `path` is not a valid file. + pub async fn connect(path: impl Into) -> DbResult { + let path = path.into(); + + let connection_string = format!( "sqlite://{}", path.canonicalize() .map_err(|_| DbError::NotFound { not_found_at: path.to_string_lossy().to_string() })? .to_string_lossy() - )}; + ); debug!("connecting to {connection_string}"); diff --git a/crates/db/tests/common/mod.rs b/crates/db/tests/common/mod.rs new file mode 100644 index 0000000..6537e30 --- /dev/null +++ b/crates/db/tests/common/mod.rs @@ -0,0 +1,24 @@ +use std::{ + fs::{File, create_dir_all}, + path::PathBuf, +}; + +use db::Db; +use rand::RngExt; + +pub async fn fresh_test_db() -> Db { + let rand_id = { + let mut rng = rand::rng(); + let mut rand_id = [0_u8; 4]; + rand_id.fill_with(|| rng.sample(rand::distr::Alphanumeric)); + + String::from_utf8(rand_id.to_vec()).unwrap() + }; + + let path = PathBuf::from(format!("/tmp/filaments/test_db_{rand_id}")); + + create_dir_all(path.parent().unwrap()).unwrap(); + + let _ = File::create(&path).unwrap(); + Db::connect(&path).await.unwrap() +} diff --git a/crates/db/tests/task.rs b/crates/db/tests/task.rs new file mode 100644 index 0000000..6f9d7ed --- /dev/null +++ b/crates/db/tests/task.rs @@ -0,0 +1,48 @@ +//! Testing task functionality with the database abstraction. + +use db::entity::{group, prelude::*}; +use db::{ActiveValue::Set, entity::task}; +use sea_orm::ActiveModelTrait; +mod common; + +#[tokio::test] +async fn test_group_task_insert() { + let db = common::fresh_test_db().await; + + let group = group::ActiveModel { + name: Set("something".to_owned()), + color: Set("color".to_owned()), + description_path: Set("something".to_owned()), + ..Default::default() + }; + + let group: group::Model = group.insert(db.as_ref()).await.unwrap(); + + let task = task::ActiveModel { + name: Set("something".to_owned()), + description_path: Set("something".to_owned()), + group_id: Set(group.nano_id.to_owned()), + ..Default::default() + }; + + let task: task::Model = task.insert(db.as_ref()).await.unwrap(); + + let task = Task::find_by_nano_id(task.nano_id) + .inner_join(Group) + // .reverse_join(Group) + // .find_with_related(Group) + .all(db.as_ref()) + .await + .unwrap(); + + let task = Task::load() + .filter_by_nano_id(task.first().unwrap().nano_id.clone()) + .with(Group) + .one(db.as_ref()) + .await + .unwrap() + .unwrap(); + + println!("{group:#?}"); + println!("{task:#?}"); +} diff --git a/flake.lock b/flake.lock index 8288bbb..6d95aa3 100644 --- a/flake.lock +++ b/flake.lock @@ -8,11 +8,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1773818109, - "narHash": "sha256-Wsk92HrZODmCgBb+v7XfTMUAIEhqU+Obwj+09IKRTpU=", + "lastModified": 1774163246, + "narHash": "sha256-gzlqyLjP44LWraUd3Zn4xrQKOtK+zcBJ77pnsSUsxcM=", "owner": "nix-community", "repo": "fenix", - "rev": "b8b443c5a1bd8dd99df899b4ac786a7f410193e5", + "rev": "4cd28929c68cae521589bc21958d3793904ed1e2", "type": "github" }, "original": { @@ -23,12 +23,12 @@ }, "nixpkgs": { "locked": { - "lastModified": 1773734432, - "narHash": "sha256-IF5ppUWh6gHGHYDbtVUyhwy/i7D261P7fWD1bPefOsw=", - "rev": "cda48547b432e8d3b18b4180ba07473762ec8558", - "revCount": 964459, + "lastModified": 1773821835, + "narHash": "sha256-TJ3lSQtW0E2JrznGVm8hOQGVpXjJyXY2guAxku2O9A4=", + "rev": "b40629efe5d6ec48dd1efba650c797ddbd39ace0", + "revCount": 964859, "type": "tarball", - "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.964459%2Brev-cda48547b432e8d3b18b4180ba07473762ec8558/019cff27-f088-710d-b729-7d70ce441bc3/source.tar.gz" + "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.964859%2Brev-b40629efe5d6ec48dd1efba650c797ddbd39ace0/019d03e9-2959-7276-adaa-d074e96422de/source.tar.gz" }, "original": { "type": "tarball", @@ -44,11 +44,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1773775226, - "narHash": "sha256-413aE+fhubk1GA2v4IlRrpdZZzW/b89wJGuDfZCVtEs=", + "lastModified": 1774097238, + "narHash": "sha256-hcujm/qEX4RUybdBCrQKdQNqTRYDItmnbjJRP5ky5vc=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "4eac290b58a70961e78f2e0c04f61a08b995b2cb", + "rev": "76de1de27c0ca1329bc41324edab22c82d69e779", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 7e5be98..7b2d7c0 100644 --- a/flake.nix +++ b/flake.nix @@ -43,6 +43,29 @@ { overlays.default = final: prev: { + + sea-orm-cli = final.rustPlatform.buildRustPackage rec { + pname = "sea-orm-cli"; + version = "2.0.0-rc.37"; + + src = final.fetchCrate { + inherit pname version; + + sha256 = "sha256-YbP85rVO41S7ZPWSpVz3jICLAEU8H/a2axJBtdFRuWY="; + + }; + + cargoHash = "sha256-6lOXyaNxrIfCI3T9nIPR76rhQXvRzSVQUsPRjo5abmI="; + + nativeBuildInputs = [ final.pkg-config ]; + + buildInputs = [ + final.openssl + ]; + + doCheck = false; # Skip tests to speed up the build + }; + rustToolchain = with inputs.fenix.packages.${prev.stdenv.hostPlatform.system}; combine ( @@ -72,6 +95,7 @@ cargo-edit cargo-watch rust-analyzer + sea-orm-cli bacon diff --git a/justfile b/justfile index 28de751..b82c4ad 100644 --- a/justfile +++ b/justfile @@ -22,17 +22,37 @@ test: # Only used to build / generate entities -dev-db := "sqlite:///" + justfile_directory() + "/target/dev.db" +dev-db := justfile_directory() + "/target/dev.db" +dev-db-url := "sqlite:///" + dev-db # build entities from migrations [working-directory:"crates/db"] entity: - touch ../../target/dev.db - cd migration && cargo run -- -u {{dev-db}} + # create the dev db + rm -f {{dev-db}} + touch {{dev-db}} + + # run the migration + cd migration && cargo run -- -u {{dev-db-url}} + + # generate entity files based off the migraiton sea-orm-cli generate entity \ - --database-url {{dev-db}} \ + --database-url {{dev-db-url}} \ --output-dir ./src/entity \ - # --expanded-format # add flag if expanded format is needed for debugging + --entity-format=dense # add flag if expanded format is needed for debugging + + # add migraton::types to every file in entity + sed -i '4i use migration::types::*;' ./src/entity/*.rs + + # replace elementary types with specific ones + sed -i 's/pub nano_id: String/pub nano_id: NanoId/g' ./src/entity/*.rs + sed -i 's/pub priority: String/pub priority: Priority/g' ./src/entity/*.rs + + # replace parent_group_id with proper nano_id + sed -i 's/pub parent_group_id: Option/pub parent_group_id: Option/g' ./src/entity/*.rs + + # replace group_id with nano_id + sed -i 's/pub group_id: String/pub group_id: NanoId/g' ./src/entity/*.rs diff --git a/src/cli.rs b/src/cli.rs index 8696a0a..71cbcaf 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,4 @@ -use clap::Parser; +use clap::{Parser, Subcommand}; use crate::config::{get_config_dir, get_data_dir}; @@ -12,8 +12,46 @@ pub struct Cli { /// Frame rate, i.e. number of frames per second #[arg(short, long, value_name = "FLOAT", default_value_t = 60.0)] pub frame_rate: f64, + + #[command(subcommand)] + pub command: Option, } +#[derive(Subcommand, Debug)] +pub enum Commands { + /// Manage TARS groups. + // #[command(subcommand)] + // Group(GroupSubcommand), + + /// Manage TARS tasks. + // #[command(subcommand)] + // Task(TaskSubcommand), + + /// simple testing stuff + Test, + // Imports bulk data into TARS + // NOTE: By default the importer will fill in fields with + // default values if they arent present / aren't able to be + // parsed properly + // Import(ImportArgs), +} + +// #[derive(Subcommand, Debug)] +// /// Subcommand to manage tars groups. +// pub enum GroupSubcommand { +// /// Add a group. +// Add(GroupAddArgs), +// /// List groups. +// List(GroupListArgs), +// } + +// #[derive(Debug, Args)] +// pub struct ExportArgs { +// #[arg(short, long, default_value = "./tars.json")] +// /// The file-path for data to pe put into. +// pub out_file: PathBuf, +// } + const VERSION_MESSAGE: &str = concat!( env!("CARGO_PKG_VERSION"), "-", diff --git a/src/main.rs b/src/main.rs index f7de8c1..907ee74 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,8 +2,9 @@ //! My (suri.codes) personal-knowledge-system, with deeply integrated task tracking and long term goal planning capabilities. //! -use clap::Parser; use crate::{app::App, cli::Cli}; +use clap::Parser; +use db::Db; mod app; mod cli; @@ -21,9 +22,20 @@ async fn main() -> color_eyre::Result<()> { logging::init()?; let args = Cli::parse(); - let mut app = App::new(args.tick_rate, args.frame_rate); - app.run().await?; + let _db = Db::connect("/tmp/filaments/test_db.sqlite").await?; + + // if there is any subcommand, we want to execute that, otherwise we + // just run the app + + if let Some(command) = args.command { + match command { + cli::Commands::Test => {} + } + } else { + let mut app = App::new(args.tick_rate, args.frame_rate); + app.run().await?; + } Ok(()) }