From 36825b49507780c49504c964fd00ce8d14405ff6 Mon Sep 17 00:00:00 2001 From: Lumither Tao Date: Fri, 3 May 2024 21:40:53 +0800 Subject: [PATCH] feat(idx) add auto idx --- backend/Cargo.toml | 1 + backend/post.sql | 6 ++-- backend/src/api/post/refresh.rs | 12 +++---- backend/src/main.rs | 1 + backend/src/markdown/meta.rs | 51 +++++++++++++++++++++++++++++ backend/src/markdown/mod.rs | 1 + backend/src/model/mod.rs | 3 ++ backend/src/model/post.rs | 57 +++++++++++++++++++++++++++------ 8 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 backend/src/markdown/meta.rs create mode 100644 backend/src/markdown/mod.rs diff --git a/backend/Cargo.toml b/backend/Cargo.toml index c573188..956a5f3 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -14,3 +14,4 @@ tokio = { version = "1.37.0", features = ["full"] } uuid = { version = "1.8.0", features = ["v4", "fast-rng", "serde"] } sqlx = { version = "0.7.4", features = ["runtime-tokio", "tls-native-tls", "postgres", "chrono", "uuid"] } chrono = { version = "0.4.38", features = ["serde"] } +regex = "1.10.4" diff --git a/backend/post.sql b/backend/post.sql index fea0912..3877d12 100644 --- a/backend/post.sql +++ b/backend/post.sql @@ -2,13 +2,15 @@ CREATE TABLE IF NOT EXISTS Post ( post_id UUID PRIMARY KEY, title VARCHAR(255) NOT NULL, + summary TEXT NOT NULL, content TEXT NOT NULL, last_update TIMESTAMP ); -INSERT INTO Post (post_id, title, content, last_update) -VALUES (?1, ?2, ?3, ?4) +INSERT INTO Post (post_id, title, summary, content, last_update) +VALUES ($1, $2, $3, $4, $5) ON CONFLICT (post_id) DO UPDATE SET title = excluded.title, + summary = excluded.summary, content = excluded.content, last_update = excluded.last_update diff --git a/backend/src/api/post/refresh.rs b/backend/src/api/post/refresh.rs index e322ff9..6d59e60 100644 --- a/backend/src/api/post/refresh.rs +++ b/backend/src/api/post/refresh.rs @@ -29,30 +29,30 @@ pub async fn refresh( let post_list: Vec = md_list .into_iter() - .map(Post::from_path) + .map(|post| Post::from_path(post).unwrap()) .collect(); for post in post_list { match query( r##" -INSERT INTO Post (post_id, title, content, last_update) -VALUES ($1, $2, $3, $4) +INSERT INTO Post (post_id, title, summary, content, last_update) +VALUES ($1, $2, $3, $4, $5) ON CONFLICT (post_id) DO UPDATE SET title = excluded.title, + summary = excluded.summary, content = excluded.content, last_update = excluded.last_update "##, ) .bind(post.post_id) .bind(post.title) + .bind(post.summary) .bind(post.content) .bind(post.last_update) .execute(&db_connection) .await { - Ok(_) => { - dbg!("inserted"); - } + Ok(_) => {} Err(e) => { return Err(( StatusCode::INTERNAL_SERVER_ERROR, diff --git a/backend/src/main.rs b/backend/src/main.rs index a13378b..347ea6f 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -12,6 +12,7 @@ use crate::api::post::refresh::refresh; mod api; mod model; +mod markdown; #[tokio::main] async fn main() -> Result<(), Box> { diff --git a/backend/src/markdown/meta.rs b/backend/src/markdown/meta.rs new file mode 100644 index 0000000..46e70b2 --- /dev/null +++ b/backend/src/markdown/meta.rs @@ -0,0 +1,51 @@ +use std::collections::HashMap; + +use regex::Regex; + +pub fn parse_meta(md_content: &str) -> HashMap { + let mut fields: HashMap = HashMap::new(); + let match_regex = Regex::new(r"(?s)---\n(.*\n)---\n").unwrap(); + if let Some(front_matter) = match_regex.captures(md_content) { + let fm_content = front_matter.get(1).unwrap().as_str(); + for line in fm_content.lines() { + if let Some((k, v)) = extract_kv(line) { + fields.insert(k, v); + } + } + } + fields +} + +fn extract_kv(line: &str) -> Option<(String, String)> { + let split: Vec<&str> = line.splitn(2, ':').map(|s| s.trim()).collect(); + if split.len() == 2 { + let key = split[0].to_string(); + let value = split[1].to_string(); + Some((key, value)) + } else { + None + } +} + +#[cfg(test)] +mod meta_test { + use std::error::Error; + + use crate::markdown::meta::parse_meta; + + #[test] + fn test_parse_meta_front_matter() -> Result<(), Box> { + let parsed_meta = parse_meta( + r##" +--- +title: Hello World! +tags: [ "test", "hello_world" ] +--- + "## + ); + dbg!(&parsed_meta); + assert_eq!(parsed_meta.get("title"), Some(&"Hello World!".to_string())); + assert_eq!(parsed_meta.get("tags"), Some(&r#"[ "test", "hello_world" ]"#.to_string())); + Ok(()) + } +} diff --git a/backend/src/markdown/mod.rs b/backend/src/markdown/mod.rs new file mode 100644 index 0000000..6b50816 --- /dev/null +++ b/backend/src/markdown/mod.rs @@ -0,0 +1 @@ +pub mod meta; diff --git a/backend/src/model/mod.rs b/backend/src/model/mod.rs index 94f60d1..234d051 100644 --- a/backend/src/model/mod.rs +++ b/backend/src/model/mod.rs @@ -9,6 +9,9 @@ pub mod post; pub struct Post { pub post_id: Uuid, pub title: String, + pub summary: String, pub content: String, pub last_update: NaiveDateTime, } + + diff --git a/backend/src/model/post.rs b/backend/src/model/post.rs index d50b84c..28e6bcf 100644 --- a/backend/src/model/post.rs +++ b/backend/src/model/post.rs @@ -1,16 +1,55 @@ -use chrono::Utc; +use std::{env, fs}; +use std::error::Error; +use std::process::Command; +use std::str; + +use chrono::{NaiveDateTime, Utc}; use uuid::Uuid; +use crate::markdown::meta::parse_meta; use crate::model::Post; -impl super::Post { - pub fn from_path(path: String) -> Self { - // todo: remove test - Post { +impl Post { + pub fn from_path(path: String) -> Result> { + let md_content = fs::read_to_string(&path)?; + let meta = parse_meta(&md_content); + + let title = match meta.get("title") { + None => "Title Not Found".to_string(), + Some(title) => title.to_owned(), + }; + let summary = match meta.get("summary") { + None => "".to_string(), + Some(summary) => summary.to_owned(), + }; + + let git_output = Command::new("git") + .arg("--no-pager") + .arg("log") + .arg("-1") + .arg("--format=%cI") + .arg("--") + .current_dir(env::var("GIT_WORK_DIR")?) + .arg(&path) + .output() + .expect("Failed to execute git command"); + + let last_update = if git_output.status.success() { + NaiveDateTime::parse_from_str( + str::from_utf8(&git_output.stdout).unwrap().trim_end(), + "%Y-%m-%dT%H:%M:%S%z", + ) + .unwrap_or_else(|_| Utc::now().naive_utc()) + } else { + Utc::now().naive_utc() + }; + + Ok(Post { post_id: Uuid::new_v4(), - title: "test title".to_string(), - content: "test content".to_string(), - last_update: Utc::now().naive_utc(), - } + title, + summary, + content: md_content, + last_update, + }) } }