My personal-knowledge-system, with deeply integrated task tracking and long term goal planning capabilities.
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: zettelid wrapper around nanoid

+81 -4
+8
crates/dto/migration/src/types/nano_id.rs
··· 1 + use std::str::FromStr as _; 2 + 1 3 use nanoid::nanoid; 2 4 use sea_orm::DeriveValueType; 3 5 ··· 44 46 Ok(Self(s.to_owned())) 45 47 } 46 48 } 49 + 50 + impl From<&str> for NanoId { 51 + fn from(value: &str) -> Self { 52 + NanoId::from_str(value).unwrap() 53 + } 54 + }
+1
src/types/mod.rs
··· 9 9 10 10 mod zettel; 11 11 pub use zettel::Zettel; 12 + // pub use zettel::ZettelId; 12 13 13 14 mod group; 14 15 pub use group::Group;
+72 -4
src/types/zettel.rs
··· 1 1 use dto::{DateTime, TagEntity, ZettelActiveModel, ZettelEntity, ZettelModelEx}; 2 - use std::path::PathBuf; 2 + use std::{ 3 + fmt::Display, 4 + path::{Path, PathBuf}, 5 + }; 3 6 4 - use color_eyre::eyre::Result; 7 + use color_eyre::eyre::{Error, Result, eyre}; 5 8 use dto::NanoId; 6 9 use tokio::{fs::File, io::AsyncWriteExt}; 7 10 ··· 15 18 pub struct Zettel { 16 19 /// Should only be constructed from models. 17 20 _private: (), 18 - pub id: NanoId, 21 + pub id: ZettelId, 19 22 pub title: String, 20 23 /// a workspace-local file path, needs to be canonicalized before usage 21 24 pub file_path: PathBuf, 22 25 pub created_at: DateTime, 23 26 pub tags: Vec<Tag>, 24 27 } 28 + 29 + /// A `ZettelId` is essentially a `NanoId`, 30 + /// with some `Zettel` specific helpers written 31 + /// onto it 32 + #[derive(Debug, Clone)] 33 + pub struct ZettelId(NanoId); 25 34 26 35 impl Zettel { 27 36 pub async fn new(title: impl Into<String>, ws: &Workspace) -> Result<Self> { ··· 102 111 103 112 Self { 104 113 _private: (), 105 - id: value.nano_id, 114 + id: value.nano_id.into(), 106 115 title: value.title, 107 116 file_path: value.file_path.into(), 108 117 created_at: value.created_at, ··· 110 119 } 111 120 } 112 121 } 122 + 123 + impl From<&str> for ZettelId { 124 + fn from(value: &str) -> Self { 125 + Self(NanoId::from(value)) 126 + } 127 + } 128 + 129 + impl From<&NanoId> for ZettelId { 130 + fn from(value: &NanoId) -> Self { 131 + value.clone().into() 132 + } 133 + } 134 + 135 + impl From<NanoId> for ZettelId { 136 + fn from(value: NanoId) -> Self { 137 + Self(value) 138 + } 139 + } 140 + 141 + impl TryFrom<PathBuf> for ZettelId { 142 + type Error = Error; 143 + 144 + fn try_from(value: PathBuf) -> Result<Self, Self::Error> { 145 + let path = value.as_path(); 146 + path.try_into() 147 + } 148 + } 149 + 150 + impl TryFrom<&Path> for ZettelId { 151 + type Error = Error; 152 + 153 + fn try_from(value: &Path) -> Result<Self, Self::Error> { 154 + let extension = value 155 + .extension() 156 + .and_then(|ext| ext.to_str()) 157 + .ok_or_else(|| eyre!("Unable to turn file extension into string".to_owned(),))?; 158 + 159 + if extension != "md" { 160 + return Err(eyre!(format!("Wrong extension: {extension}, expected .md"))); 161 + } 162 + 163 + let id: Self = value 164 + .file_name() 165 + .ok_or_else(|| eyre!("Invalid File Name!".to_owned()))? 166 + .to_str() 167 + .ok_or_else(|| eyre!("File Name cannot be translated into str!".to_owned(),))? 168 + .strip_suffix(".md") 169 + .expect("we statically verify this right above") 170 + .into(); 171 + 172 + Ok(id) 173 + } 174 + } 175 + 176 + impl Display for ZettelId { 177 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 178 + f.write_str(&self.0.to_string()) 179 + } 180 + }